using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using FireStarterModeller.BO;
using Habanero.Base;
using Habanero.BO;
using Habanero.BO.ClassDefinition;
using Habanero.Faces.Base;
using Habanero.Faces.Win;
using DockStyle=Habanero.Faces.Base.DockStyle;

namespace FireStarterModeller.UI.Relationship
{
    public class DMRelationshipPanelInfoControl : UserControlWin, IBOEditorControl
    {
        private readonly IControlFactory _controlFactory;
        //private DMRelationship _dmRelationship;
        private IPanelInfo _detailPanelInfo;
        private IPanelInfo _multipleDetailPanelInfo;
        private IPanel _moreDetailPanel;
        private IPanel _detailPanel;
        private IGroupBox _detailsGroupBox;
        private SortPropertySelectorMapper _sortPropertySelectorMapper;

        public PanelInfo.FieldInfo RelatedClassFieldInfo { get; private set; }
        public PanelInfo.FieldInfo RelationshipNameFieldInfo { get; private set; }
        public PanelInfo.FieldInfo RelationshipTypeFieldInfo { get; private set; }
        //public ICheckBox OwningBOHasFKCheckBox { get; private set; }
        //public IComboBox RelationshipTypeComboBox { get; private set; }
        //public ITextBox RelationshipNameTextBox { set; get; }
        //public IComboBox RelatedClassComboBox { set; get; }

        public IControlFactory ControlFactory { get { return _controlFactory; } }
        public IPanelInfo DetailPanelInfo { get { return _detailPanelInfo; } }
        public IPanelInfo MultipleDetailPanelInfo { get { return _multipleDetailPanelInfo; } }
        public IPanel MoreDetailPanel { get { return _moreDetailPanel; } }

        public DMRelationshipPanelInfoControl(IControlFactory controlFactory)
        {
            if (controlFactory == null) throw new ArgumentNullException("controlFactory");
            _controlFactory = controlFactory;
            InitialiseControl();
        }

        private void InitialiseControl()
        {
            Width = 320;
            IGroupBox detailPanelGroupBox = SetupRelationshipDetailsGroupBox();
            BorderLayoutManager layoutManager = _controlFactory.CreateBorderLayoutManager(this);
            layoutManager.AddControl(detailPanelGroupBox, BorderLayoutManager.Position.North);
            UpdateState();
        }

        private IGroupBox SetupRelationshipDetailsGroupBox()
        {
            _detailsGroupBox = _controlFactory.CreateGroupBox("Relationship Details");
            
            IPanel groupBoxPanel = _controlFactory.CreatePanel();
            groupBoxPanel.Dock = DockStyle.Fill;
            
            _detailsGroupBox.Controls.Add(groupBoxPanel);
            
            PanelBuilder panelBuilder = new PanelBuilder(_controlFactory);
            _detailPanel = SetupDetailPanel(panelBuilder);

            _moreDetailPanel = _controlFactory.CreatePanel();
            _moreDetailPanel.Visible = false;
            _moreDetailPanel.Size = new Size(10,1);
            IPanel multipleDetailPanel = SetupMultipleDetailPanel(panelBuilder);
            _moreDetailPanel.MinimumSize = multipleDetailPanel.MinimumSize;
//            multipleDetailPanel.Dock = DockStyle.Fill;
            multipleDetailPanel.Width = 380;
            _moreDetailPanel.Controls.Add(multipleDetailPanel);

            //ColumnLayoutManager layoutManager = new ColumnLayoutManager(groupBoxPanel, _controlFactory) { ColumnCount = 1 };
            //layoutManager.AddControl(new PanelWin { Size = new Size(10, 10), BorderStyle = BorderStyle.FixedSingle });
            //layoutManager.AddControl(new PanelWin { Size = new Size(10, 10), BorderStyle = BorderStyle.FixedSingle });

            //layoutManager.AddControl(detailPanel);
            //layoutManager.AddControl(_moreDetailPanel);

            _moreDetailPanel.Dock = DockStyle.Bottom;
            groupBoxPanel.Controls.Add(_moreDetailPanel);

            _detailPanel.Width = 380;
//            _detailPanel.Dock = DockStyle.Fill;
            groupBoxPanel.Controls.Add(_detailPanel);

            return _detailsGroupBox;
        }

        private IPanel SetupDetailPanel(PanelBuilder panelBuilder)
        {
            _detailPanelInfo = panelBuilder.BuildPanelForForm(ClassDef.Get<DMRelationship>().UIDefCol["default"].UIForm);
            RelationshipNameFieldInfo = _detailPanelInfo.FieldInfos["RelationshipName"];
            RelationshipTypeFieldInfo = _detailPanelInfo.FieldInfos["RelationshipType"];
            RelatedClassFieldInfo = _detailPanelInfo.FieldInfos["ReverseRelationship.ClassDM"];
            return _detailPanelInfo.Panel;
        }

        private IPanel SetupMultipleDetailPanel(PanelBuilder panelBuilder)
        {
            _multipleDetailPanelInfo = panelBuilder.BuildPanelForForm(ClassDef.Get<DMRelationship>().UIDefCol["Multiple"].UIForm);
            _sortPropertySelectorMapper = (SortPropertySelectorMapper) this._multipleDetailPanelInfo.FieldInfos["DMSortOrder"].ControlMapper;
            return _multipleDetailPanelInfo.Panel;
        }

        public DMRelationship DMRelationship
        {
            get { return (DMRelationship) _detailPanelInfo.BusinessObject; }
            set
            {
                DMRelationship oldRelationship = DMRelationship;
                DMRelationship dmRelationship = value;
                if (dmRelationship != null)
                {
                    DMClass ownerClass = (DMClass) dmRelationship.OwnerClass;
                    if (ownerClass != null && ownerClass.Solution != null)
                    {
                        RelationshipComboBoxMapper controlMapper = (RelationshipComboBoxMapper)RelatedClassFieldInfo.ControlMapper;
                        BusinessObjectCollection<DMClass> allClasses = ownerClass.Solution.AllClasses;
                        if (!ReferenceEquals(controlMapper.BusinessObjectCollection, allClasses))
                        {
                            controlMapper.IncludeBlankItem = true;
                            controlMapper.BusinessObjectCollection = allClasses;
                        }
                    }
                }
                if (oldRelationship != null)
                {
                    oldRelationship.Props["Cardinality"].Updated -= Relationship_CardinalityUpdated;
                    oldRelationship.Props["ClassID"].Updated -= ClassID_OnUpdated;
                }
                _detailPanelInfo.BusinessObject = dmRelationship;
                _multipleDetailPanelInfo.BusinessObject = dmRelationship;
                if (dmRelationship != null)
                {
                    dmRelationship.Props["Cardinality"].Updated += Relationship_CardinalityUpdated;
                }

                if (dmRelationship != null)
                {
                    SetDMPropertiesOnSortPropertyMapper();
                    IDMRelationship reverseRelationship = dmRelationship.ReverseRelationship;
                    if (reverseRelationship != null) reverseRelationship.Props["ClassID"].Updated += ClassID_OnUpdated;
                }
                UpdateState();
            }
        }

        private void ClassID_OnUpdated(object sender, BOPropEventArgs args)
        {
            SetDMPropertiesOnSortPropertyMapper();
        }

        private void SetDMPropertiesOnSortPropertyMapper()
        {
            try
            {
                DMRelationship relationship = ((DMRelationship) this.BusinessObject);
                if (relationship == null) 
                {
                    _sortPropertySelectorMapper.DMProperties = null;
                    return;
                }
                DMClass relatedClass = (DMClass) relationship.RelatedClass;
                if (relatedClass == null)
                {
                    _sortPropertySelectorMapper.DMProperties = null;
                }
                else
                {
                    //_sortPropertySelectorMapper.DMProperties = relatedClass.AllProperties;
                    _sortPropertySelectorMapper.DMProperties = relatedClass.GetSortOrderProperties();
                }
            }
            catch (Exception ex)
            {
                GlobalRegistry.UIExceptionNotifier.Notify(ex, "", "Error ");
            }
        }

        private SortPropertySelectorMapper SortPropertySelectorMapper
        {
            get { return _sortPropertySelectorMapper; }
        }

        private void Relationship_CardinalityUpdated(object sender, BOPropEventArgs e)
        {
            UpdateState();
        }


        private void UpdateState()
        {
            bool showMultipleProps = DMRelationship != null && DMRelationship.Cardinality == Cardinality.Multiple;
            Size minimumSize = new Size(_detailPanel.MinimumSize.Width + 10, _detailPanel.MinimumSize.Height + 20);
            int newHeight = minimumSize.Height;
            if (showMultipleProps)
            {
                newHeight = newHeight + _moreDetailPanel.MinimumSize.Height - 5;
            }
            if (!showMultipleProps) _moreDetailPanel.Visible = false;
            _detailsGroupBox.MinimumSize = minimumSize;
            this.MinimumSize = minimumSize;
            this.Height = newHeight;
            _detailsGroupBox.Height = newHeight;
            if (showMultipleProps) _moreDetailPanel.Visible = true;
        }

        #region Implementation of IBusinessObjectControl

        /// <summary>
        ///             Gets or sets the business object being represented
        /// </summary>
        public IBusinessObject BusinessObject
        {
            get { return DMRelationship; }
            set { DMRelationship = (DMRelationship) value; }
        }

        #endregion

        #region Implementation of IBOEditorControl

        /// <summary>
        ///             Displays any errors or invalid fields associated with the BusinessObjectInfo
        ///             being edited.  A typical use would involve activating the ErrorProviders
        ///             on a BO panel.
        /// </summary>
        public void DisplayErrors()
        {
            this._detailPanelInfo.ApplyChangesToBusinessObject();
        }

        /// <summary>
        ///             Hides all the error providers.  Typically used where a new object has just
        ///             been added and the interface is being cleaned up.
        /// </summary>
        public void ClearErrors()
        {
            this._detailPanelInfo.ClearErrorProviders();
        }

        #endregion

        #region Implementation of IBOEditorControl

        /// <summary>
        ///             Applies any changes that have occured in any of the Controls on this control's to their related
        ///             Properties on the Business Object.
        /// </summary>
        public void ApplyChangesToBusinessObject()
        {
            this._detailPanelInfo.ApplyChangesToBusinessObject();
        }

        /// <summary>
        ///             Does the business object controlled by this control or any of its Aggregate or Composite children have and Errors.
        /// </summary>
        public bool HasErrors
        {
            get { throw new System.NotImplementedException(); }
        }

        /// <summary>
        ///             Does the Business Object controlled by this control or any of its Aggregate or Composite children have and warnings.
        /// </summary>
        public bool HasWarning
        {
            get { throw new System.NotImplementedException(); }
        }

        /// <summary>
        ///              Returns a list of all warnings for the business object controlled by this control or any of its children.
        /// </summary>
        public ErrorList Errors
        {
            get { throw new System.NotImplementedException(); }
        }

        /// <summary>
        ///             Does the business object being managed by this control have any edits that have not been persisted.
        /// </summary>
        /// <returns>
        /// </returns>
        public bool IsDirty
        {
            get { throw new System.NotImplementedException(); }
        }

        /// <summary>
        ///             Returns a list of all warnings for the business object controlled by this control or any of its children.
        /// </summary>
        /// <returns>
        /// </returns>
        public ErrorList Warnings
        {
            get { throw new System.NotImplementedException(); }
        }

        #endregion
    }
}
